%parse-param { std::unique_ptr<ast::BaseAST>& root } 
%code requires {
    #include "ast.h"
    #include <memory>
}

%{

#include <fstream>
#include "ast.h"
#include <memory>
#include <iostream>
#include <string>
#include <vector>

extern int yylex();
extern int yyparse(std::unique_ptr<ast::BaseAST>& root);
void yyerror(std::unique_ptr<ast::BaseAST>& ast, const char* msg); 
extern FILE* yyin;

using namespace ast;

ast::ExprAST* create_binary_expr(ast::OpType op, ast::BaseAST* left,ast::BaseAST* right) ;
ast::ExprAST* create_unary_expr(ast::OpType op, ast::BaseAST* operand);

%}
%union {
  std::string *str_val;
  int int_val;
  ast::BaseAST *ast;
  ast::Type type;
}
%destructor { /* 什么也不做 */ } <ast>
//终结符
%token INT VOID IF ELSE WHILE BREAK CONTINUE RETURN ASSIGN
%token PLUS MINUS TIMES DIV MOD OR AND NOT LT GT EQ NE GE LE 
%token LPAREN RPAREN LBRACE RBRACE COMMA SEMICOLON
%token <str_val> ID
%token <int_val> NUM

//非终结符
%type <ast> comp_unit
%type <ast> func_defs params args stmts block
%type <type> type
%type <ast> func_def param stmt
%type <ast> assign_stmt def_stmt if_stmt while_stmt
%type <ast> expr l_or_expr l_and_expr rel_expr add_expr mul_expr unary_expr primary_expr
%type <ast> call_expr arg


%nonassoc IFX;  // 添加优先级声明
%nonassoc ELSE;

%start comp_unit
%%

comp_unit: func_defs {
    auto unit = std::make_unique<ast::CompUnitAST>();
    unit -> func_defs = std::unique_ptr<BaseAST>($1);
    root = std::move(unit);  // 赋值给引用参数
};

func_defs: func_def{
    auto lst = new ListAST();
    lst -> items.push_back(std::unique_ptr<BaseAST>($1));
    $$ = lst;
}
| func_defs func_def{
    auto list = static_cast<ListAST*>($1);
    list->items.push_back(std::unique_ptr<BaseAST>($2));
    $$ = list;
};

func_def: type ID LPAREN RPAREN block{
    auto func = new FuncDefAST();
    func -> type = $1;
    auto Id = new IdAST($2);
    func -> id = std::unique_ptr<BaseAST>(Id); 
    func -> params = nullptr;
    func -> stmts = std::unique_ptr<BaseAST>($5);
    $$ = func;
} 
| type ID LPAREN params RPAREN block{
    auto func = new FuncDefAST();
    func -> type = $1;
    auto Id = new IdAST($2);
    func -> id = std::unique_ptr<BaseAST>(Id); 
    func -> params = std::unique_ptr<BaseAST>($4);
    func -> stmts = std::unique_ptr<BaseAST>($6);
    $$ = func;
};

type: INT{ $$ = ast::TYPE_INT; }
| VOID { $$ = ast:: TYPE_VOID; };

params:param{
    auto lst = new ListAST();
    lst -> items.push_back(std::unique_ptr<BaseAST>($1));
    $$ = lst;
}
| params COMMA param{
    auto lst = static_cast<ListAST*>($1);
    lst -> items.push_back(std::unique_ptr<BaseAST>($3));
    $$ = lst;
};

param :INT ID{
    auto p  = new ParamAST();
    auto Id = new IdAST($2);
    p -> id = std::unique_ptr<BaseAST>(Id);
    $$ = p;
};

block: LBRACE RBRACE {
    // 空语句块
    $$ = new ListAST();
}
| LBRACE stmts RBRACE {
    // 有语句的块
    $$ = $2;
};

stmts: stmt{
    auto lst = new ListAST();
    lst -> items.push_back(std::unique_ptr<BaseAST>($1));
    $$ = lst;
}
| stmts stmt {
    auto lst = static_cast<ListAST*>($1);
    lst -> items.push_back(std::unique_ptr<BaseAST>($2));
    $$ = lst;
};

//stmt
stmt: block {  // 块语句
    auto stmt_ast = new StmtAST();
    stmt_ast->stmt_type = ast::STMT_BLOCK;
    stmt_ast->stmt = std::unique_ptr<BaseAST>($1);
    $$ = stmt_ast;
}
| SEMICOLON {  // 空语句
    auto stmt_ast = new StmtAST();
    stmt_ast->stmt_type = ast::STMT_NULL;
    stmt_ast->stmt = nullptr;
    $$ = stmt_ast;
}
| expr SEMICOLON {  // 表达式语句
    auto stmt_ast = new StmtAST();
    stmt_ast->stmt_type = ast::STMT_EXPR;
    stmt_ast->stmt = std::unique_ptr<BaseAST>($1);
    $$ = stmt_ast;
}
| assign_stmt {  // 赋值语句
    auto stmt_ast = new StmtAST();
    stmt_ast->stmt_type = ast::STMT_ASSIGN;
    stmt_ast->stmt = std::unique_ptr<BaseAST>($1);
    $$ = stmt_ast;
}
| def_stmt {
    auto stmt_ast = new StmtAST();
    stmt_ast->stmt_type = ast::STMT_DEF;
    stmt_ast->stmt = std::unique_ptr<BaseAST>($1);
    $$ = stmt_ast;
}
| if_stmt{
    auto stmt_ast = new StmtAST();
    stmt_ast->stmt_type = ast::STMT_IF;
    stmt_ast->stmt = std::unique_ptr<BaseAST>($1);
    $$ = stmt_ast;
}
| while_stmt{
    auto stmt_ast = new StmtAST();
    stmt_ast->stmt_type = ast::STMT_WHILE;
    stmt_ast->stmt = std::unique_ptr<BaseAST>($1);
    $$ = stmt_ast;
}
| BREAK SEMICOLON {
    auto stmt_ast = new StmtAST();
    stmt_ast->stmt_type = ast::STMT_BREAK;
    $$ = stmt_ast;
}
| CONTINUE SEMICOLON {
    auto stmt_ast = new StmtAST();
    stmt_ast->stmt_type = ast::STMT_CONT;
    $$ = stmt_ast;
}
| RETURN SEMICOLON {
    auto stmt_ast = new StmtAST();
    stmt_ast->stmt_type = ast::STMT_RET;
    stmt_ast->stmt = nullptr;
    $$ = stmt_ast;
}
| RETURN expr SEMICOLON {
    auto stmt_ast = new StmtAST();
    stmt_ast->stmt_type = ast::STMT_RET;
    stmt_ast->stmt = std::unique_ptr<BaseAST>($2);
    $$ = stmt_ast;
};

// 赋值语句
assign_stmt: ID ASSIGN expr SEMICOLON {
    auto assign = new AssignStmtAST();
    auto Id = new IdAST($1);
    assign -> id = std::unique_ptr<BaseAST>(Id);
    assign -> expr = std::unique_ptr<BaseAST>($3);
    $$ = assign;
};

// 变量定义
def_stmt: INT ID ASSIGN expr SEMICOLON {
    auto def = new DefStmtAST();
    auto Id = new IdAST($2);
    def -> id = std::unique_ptr<BaseAST>(Id);
    def -> expr = std::unique_ptr<BaseAST>($4);
    $$ = def;
};

// if 语句
if_stmt: IF LPAREN expr RPAREN stmt %prec IFX {
    auto if_exp = new IfStmtAST();
    if_exp -> expr = std::unique_ptr<BaseAST>($3);
    if_exp -> then_stmt = std::unique_ptr<BaseAST>($5);
    if_exp -> else_stmt = nullptr;
    $$ = if_exp;
}
| IF LPAREN expr RPAREN stmt ELSE stmt {
    auto if_exp = new IfStmtAST();
    if_exp -> expr = std::unique_ptr<BaseAST>($3);
    if_exp -> then_stmt = std::unique_ptr<BaseAST>($5);
    if_exp -> else_stmt = std::unique_ptr<BaseAST>($7);
    $$ = if_exp;
};

// while 语句
while_stmt: WHILE LPAREN expr RPAREN stmt {
    auto while_exp  = new WhileStmtAST();
    while_exp -> expr = std::unique_ptr<BaseAST>($3);
    while_exp -> stmt = std::unique_ptr<BaseAST>($5);
    $$ = while_exp;
};

expr: l_or_expr { $$ = $1; };

l_or_expr: l_and_expr { $$ = $1; }
| l_or_expr OR l_and_expr {
    $$ = create_binary_expr(ast::OP_OR, $1, $3);
};

l_and_expr: rel_expr{ $$ = $1; }
| l_and_expr AND rel_expr{
    $$ = create_binary_expr(ast::OP_AND, $1, $3);
};

rel_expr: add_expr{ $$ = $1; }
| rel_expr LT add_expr{
    $$ = create_binary_expr(ast::OP_LT, $1, $3);
}
| rel_expr GT add_expr{
    $$ = create_binary_expr(ast::OP_GT, $1, $3);
}
| rel_expr LE add_expr{
    $$ = create_binary_expr(ast::OP_LE, $1, $3);
}
| rel_expr GE add_expr{
    $$ = create_binary_expr(ast::OP_GE, $1, $3);
}
| rel_expr EQ add_expr{
    $$ = create_binary_expr(ast::OP_EQ, $1, $3);
}
| rel_expr NE add_expr{
    $$ = create_binary_expr(ast::OP_NE, $1, $3);
};

add_expr: mul_expr{ $$ = $1; }
| add_expr PLUS mul_expr {
    $$ = create_binary_expr(ast::OP_PLUS, $1, $3);
}
|add_expr MINUS mul_expr {
    $$ = create_binary_expr(ast::OP_MINUS, $1, $3);
};

mul_expr: unary_expr{ $$ = $1; }
| mul_expr TIMES unary_expr{
     $$ = create_binary_expr(ast::OP_TIMES, $1, $3);
}
|mul_expr DIV unary_expr{
     $$ = create_binary_expr(ast::OP_DIV, $1, $3);
}
|mul_expr MOD unary_expr{
     $$ = create_binary_expr(ast::OP_MOD, $1, $3);
};

unary_expr: primary_expr{ $$ = $1; }
| PLUS unary_expr{
    $$ = create_unary_expr(ast::OP_PLUS, $2);
}
| MINUS unary_expr{
    $$ = create_unary_expr(ast::OP_MINUS, $2);
}
| NOT unary_expr{
    $$ = create_unary_expr(ast::OP_NOT, $2);
}

primary_expr: ID {
    // 标识符
    auto id = new IdAST($1);
    auto expr = new ExprAST();
    expr->expr_type = ast::EXPR_ID;
    expr->expr = std::unique_ptr<BaseAST>(id);
    $$ = expr;
}
| NUM {
    // 数字字面量
    auto num = new NumAST($1);
    auto expr = new ExprAST();
    expr->expr_type = ast::EXPR_NUM;
    expr->expr = std::unique_ptr<BaseAST>(num);
    $$ = expr;
}
| LPAREN expr RPAREN {
    // 括号表达式
    auto expr_ast = new ExprAST();
    expr_ast->expr_type = ast::EXPR_PAREN;
    expr_ast->expr = std::unique_ptr<BaseAST>($2);
    $$ = expr_ast;
}
| call_expr {
    // 函数调用
    auto expr_ast = new ExprAST();
    expr_ast->expr_type = ast::EXPR_CALL;
    expr_ast->expr = std::unique_ptr<BaseAST>($1);
    $$ = expr_ast;
};

call_expr: ID LPAREN RPAREN {
    // 无参数调用
    auto callexp = new CallExprAST();
    auto Id = new IdAST($1);
    callexp -> id = std::unique_ptr<BaseAST>(Id);
    callexp -> args = nullptr;
    $$ = callexp;
}
| ID LPAREN args RPAREN {
    // 带参数调用
    auto callexp  = new CallExprAST();
    auto Id = new IdAST($1);
    callexp -> id = std::unique_ptr<BaseAST>(Id);
    callexp -> args = std::unique_ptr<BaseAST>($3);
    $$ = callexp;
};

args: arg {
    // 单参数
    auto list = new ListAST();
    list -> items.push_back(std::unique_ptr<BaseAST>($1));
    $$ = list;
}
| args COMMA arg {
    // 多参数
    auto lst = static_cast<ListAST*>($1);
    lst -> items.push_back(std::unique_ptr<BaseAST>($3));
    $$ = lst;
};

arg: expr{
    auto arg = new ArgAST();
    arg -> expr = std::unique_ptr<BaseAST>($1);
    $$ = arg;
};
%%
// 创建二元表达式
ast::ExprAST* create_binary_expr(ast::OpType op, ast::BaseAST* left, ast::BaseAST* right) {
    auto binary = new BinaryExprAST();
    binary->op = op;
    binary->expr1 = std::unique_ptr<BaseAST>(left);
    binary->expr2 = std::unique_ptr<BaseAST>(right);
    
    auto expr = new ExprAST();
    expr->expr_type = ast::EXPR_BINARY;
    expr->expr = std::unique_ptr<BaseAST>(binary);
    return expr;
}

// 创建一元表达式
ast::ExprAST* create_unary_expr(ast::OpType op, ast::BaseAST* operand) {
    auto unary = new UnaryExprAST;
    unary->op = op;
    unary->expr = std::unique_ptr<BaseAST>(operand);

    auto expr = new ExprAST();
    expr->expr_type = ast::EXPR_UNARY;
    expr->expr = std::unique_ptr<BaseAST>(unary);
    return expr;
}

void yyerror(std::unique_ptr<BaseAST>& /* ast */, const char* msg) {
  std::cerr << "语法错误: " << msg << std::endl;
}
/*
int main(int argc, char* argv[]) {
    // 检查命令行参数
    if (argc != 3) {
        std::cerr << "Usage: " << argv[0] << " <input_file> <output_file>\n";
        return 1;
    }

    const char* input_file = argv[1];
    const char* output_file = argv[2];

    // 打开输入文件
    yyin = fopen(input_file, "r");
    if (!yyin) {
        perror("Failed to open input file");
        return 1;
    }

    // 创建根节点
    std::unique_ptr<ast::BaseAST> root;
    
    // 执行解析
    int parseResult = yyparse(root);
    fclose(yyin);

    if (parseResult != 0) {
        std::cerr << "Parsing failed with errors\n";
        return 1;
    }

    // 打开输出文件
    std::ofstream out(output_file);
    if (!out) {
        std::cerr << "Failed to open output file: " << output_file << std::endl;
        return 1;
    }

    // 重定向输出到文件
    std::streambuf* cout_buf = std::cout.rdbuf();
    std::cout.rdbuf(out.rdbuf());

    // 输出AST
    if (root) {
        std::cout << "=== AST Dump ===\n";
        root->Dump();
        std::cout << "================\n";
    } else {
        std::cout << "No AST generated\n";
    }

    // 恢复标准输出
    std::cout.rdbuf(cout_buf);
    out.close();

    return 0;
}
*/